package com.example.tys.baseapplication.shell

import android.util.Log
import java.io.*
import java.lang.Exception
import java.util.regex.Matcher
import java.util.regex.Pattern


/**
 * sh xxx.sh 流
 */
class Shell {

    companion object {
        private const val TAG = "Shell"
        private const val END_COMMAND_END = "end_command_end"
        private const val END_COMMAND_END_REGEX = "(?<=${END_COMMAND_END})\\S*"
    }

    private var mProcess: Process = ProcessBuilder("sh")
        .redirectErrorStream(true)
        .start()
    private var mReader: BufferedReader
    private var mWriter: BufferedWriter

    init {
        mReader = BufferedReader(InputStreamReader(mProcess.inputStream))
        mWriter = BufferedWriter(OutputStreamWriter(mProcess.outputStream))
    }


    fun exec(root: Boolean, vararg cmd: String): ArrayList<ShellCmd> {
        val ret = ArrayList<ShellCmd>()
        try {
            val execInner = execInner(cmd, root)
            ret.addAll(execInner)
        } catch (e: Exception) {
            e.printStackTrace()
        } finally {
            close()
        }
        return ret
    }


    /**
     * write
     * @param cmd String
     * @return com.example.tys.baseapplication.shell.ShellCmd
     * @throws IOException
     */
    private fun execInner(cmd: String): ShellCmd {
        return writeCmd(cmd)
    }

    private fun execInner(cmd: Array<out String>, root: Boolean = false): ArrayList<ShellCmd> {
        val result = ArrayList<ShellCmd>()
        if (cmd.isEmpty()) {
            return result
        }
        if (root) {
            val suCmd = execInner("su")
            if (suCmd.execStatus != 0) {
                return result.apply {
                    add(suCmd)
                }
            }
        }
        cmd.forEach {
            result.add(execInner(it))
        }
        return result
    }

    private fun writeCmd(cmd: String): ShellCmd {
        val shellCmd = ShellCmd(cmd)
        mWriter.write(shellCmd.toAvailableCmd())
        mWriter.newLine()
        mWriter.write("echo $END_COMMAND_END $?")
        mWriter.newLine()
        mWriter.flush()

        //执行结果
        var lineVal: String
        val resultList = arrayListOf<String>()
        while (mReader.readLine().also { line ->
                lineVal = line
            } != null && !lineVal.startsWith(END_COMMAND_END)) {
            resultList.add(lineVal)
        }
        shellCmd.outLines = resultList.toArray(Array(resultList.size) { "" })

        //退出状态 $?
        val match: Matcher
        if (Pattern.compile(END_COMMAND_END_REGEX).matcher(lineVal).also { match = it }.find()) {
            val exitVal = lineVal.substring(match.start()).trim()
            try {
                shellCmd.execStatus = exitVal.toInt()
            } catch (e: NumberFormatException) {
                Log.e(TAG, e.toString())
            }
        }
        return shellCmd
    }

    private fun close() {
        try {
            mWriter.write("\n")
            mWriter.write("exit")
            mWriter.write("\n")
            mReader.close()
            mWriter.close()
            mProcess.destroy()
        } catch (e: Exception) {
            e.printStackTrace()
            Log.e(TAG, "close exception $e")
        }
    }


}